package com.vision.sales.sv.serv;

import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.SimpleExpression;
import org.hibernate.engine.TypedValue;
import org.hibernate.type.IntegerType;
import org.hibernate.type.Type;

/**
 * 
 * @author Mark
 *
 */
public class DateExtract extends SimpleExpression {

	private static final long serialVersionUID = 1L;
	
	private String dateField;
	private String property;
	private Object value;
	private Type type;
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	public static DateExtract create(String dateField, String property, Object value, Type type, String op) {
		DateExtract expr = new DateExtract(dateField, property, value, type, op);
		return expr;
	}
	
	public static DateExtract in(String dateField, String propertyName, List<?> value) {
		DateExtract expr = new DateExtract(dateField, propertyName, value, IntegerType.INSTANCE, "IN");
		return expr;
	}
	
	public static DateExtract year(String propertyName, int value) {
		DateExtract expr = new DateExtract("YEAR", propertyName, value, IntegerType.INSTANCE, "=");
		return expr;
	}
	
	public static DateExtract month(String propertyName, int value) {
		DateExtract expr = new DateExtract("MONTH", propertyName, value, IntegerType.INSTANCE, "=");
		return expr;
	}
	
	public static DateExtract dayOfMonth(String propertyName, int value) {
		DateExtract expr = new DateExtract("DAY", propertyName, value, IntegerType.INSTANCE, "=");
		return expr;
	}
	
	// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
	
	private DateExtract(String dateField, String propertyName, Object value, Type type, String op) {
		super(propertyName, value, op);
		
		this.dateField = dateField;
		this.property = propertyName;
		this.value = value;
		this.type = type;
	}
	
	@Override
	public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery)
			throws HibernateException {
		String[] columns = criteriaQuery.findColumns(property, criteria);
		
		StringBuilder fragment = new StringBuilder();
		if (columns.length>1) fragment.append('(');
		
		for ( int i = 0; i < columns.length; i++ ) {
			fragment.append( "EXTRACT(" + dateField + " FROM " + columns[i] + ")" );
			fragment.append( getOp() );
			
			if ((value instanceof List)) {
				List<?> list = (List<?>) value;
				fragment.append("(");
				for (int k = 0; k < list.size(); k++) {
					fragment.append(k < list.size() - 1 ? "?, " : "?");
				}
				fragment.append(")");
			} else {
				fragment.append("?");
			}
			
			if ( i < columns.length - 1 ) fragment.append(" and ");
		}
		
		if (columns.length > 1) fragment.append(')');
		
		return fragment.toString();
	}

	public TypedValue[] getTypedValues(Criteria criteria, CriteriaQuery criteriaQuery)
			throws HibernateException {
		if ( (value instanceof List) ) {
			List<?> list = (List<?>) value;
			TypedValue[] types = new TypedValue[list.size()];
			for (int i = 0; i < list.size(); i++) {
				types[i] = new TypedValue(type, list.get(i), EntityMode.POJO);
			}
			return types;
		} else {
			return new TypedValue[] { 
					new TypedValue(type, value, EntityMode.POJO)
					};
		}
	}

}
